package com.hua.api.core.framework.statement;


import org.hibernate.query.internal.NativeQueryImpl;
import org.hibernate.transform.Transformers;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Component;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import java.util.List;
import java.util.Map;


@SuppressWarnings("all")
@Component
public class EntityManagerTemplate {

    // 需注入
    @PersistenceContext
    private EntityManager em;

    public <T> List<T> query(Statement stms,Integer size, Class cls){
        Query query = createQuery(stms,size,cls);
        return query.getResultList();
    }

    public <T> List<T> query(Statement stms,Class cls){
        Query query = createQuery(stms,null,cls);
        return query.getResultList();
    }

    public List<Map<String, Object>> queryListMap(Statement stms,Integer size) {
        Query query = createQuery(stms,size);
        if (stms.isNativeSQL()) {


            query.unwrap(NativeQueryImpl.class)
                    .setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
            //返回唯一结果
        }
        return query.getResultList();
    }

    public List<Map<String, Object>> queryListMap(Statement stms) {
        Query query = createQuery(stms);
        if (stms.isNativeSQL()) {
            // java 8 使用SQLQuery.class
            query.unwrap(NativeQueryImpl.class)
                    .setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
            //返回唯一结果
        }
        return query.getResultList();
    }

    /**
     * 执行原生SQL，返回Map对象
     * @param stmt
     * @return
     * @date 2018-11-20 13:55:36
     */
    public Map<String, Object> queryNativeSQLForMap(Statement stms) {
        Query query = createQuery(stms);
        query.unwrap(NativeQueryImpl.class)
                .setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
        //返回唯一结果
        return (Map<String, Object>) query.getSingleResult();
    }

    public  List<Map<String, Object>> queryMap(Statement stms, Integer size){
        Query query = createQuery(stms,size);
        return query.getResultList();
    }

    public List<Map<String, Object>> queryMap(Statement stms){
        Query query = createQuery(stms,null);
        return query.getResultList();
    }

    public int update(Statement stms){

        Query query = stms.isNativeSQL()?em.createNativeQuery(stms.toString()):em.createQuery(stms.toString());
        List<Object> values = stms.getParams();

        if(values!=null){
            for(int i = 1;i<=values.size();i++){
                query.setParameter(i,values.get(i-1));
            }
        }

        return query.executeUpdate();
    }

    public <T> Page<T> search(Statement stms,Class cls,Pageable page){
        //总数
        Long total = total(stms);
        Query query = createPageQuery(stms,cls,page);
        return new PageImpl(query.getResultList(),page,total);
    }

    public <T> Page<T> search(Statement stms,Pageable page){
        //总数
        Long total = total(stms);
        Query query = createPageQuery(stms,page);
        return new PageImpl(query.getResultList(),page,total);
    }



    public Query createQuery(Statement stms){

        Query query = stms.isNativeSQL()?em.createNativeQuery(stms.toString()):em.createQuery(stms.toString());
        List<Object> values = stms.getParams();

        // 原生转
        if(stms.isNativeSQL()){
            query.unwrap(NativeQueryImpl.class)
                    .setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
        }
        if(values!=null){
            for(int i = 1;i<=values.size();i++){
                query.setParameter(i,values.get(i-1));
            }
        }
        return query;
    }

    public Query createQuery(Statement stms,Integer size){
        Query query = stms.isNativeSQL()?em.createNativeQuery(stms.toString()):em.createQuery(stms.toString());
        List<Object> values = stms.getParams();

        if(null!=size){
            query.setMaxResults(size);
        }

        // 原生转随想
        if(stms.isNativeSQL()){
            query.unwrap(NativeQueryImpl.class)
                    .setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
        }
        if(values!=null){
            for(int i = 1;i<=values.size();i++){
                query.setParameter(i,values.get(i-1));
            }
        }
        return query;
    }


    public Query createQuery(Statement stms,Integer size, Class cls){
        Query query = stms.isNativeSQL()?em.createNativeQuery(stms.toString()):em.createQuery(stms.toString(),cls);
        List<Object> values = stms.getParams();

        if(null!=size){
            query.setMaxResults(size);
        }

        // 原生转
        if(stms.isNativeSQL()){
            query.unwrap(NativeQueryImpl.class).setResultTransformer(Transformers.aliasToBean(cls));
        }
        if(values!=null){
            for(int i = 1;i<=values.size();i++){
                query.setParameter(i,values.get(i-1));
            }
        }

        return query;
    }

    public Query createPageQuery(Statement stms,Class cls,Pageable page){
        Query query = stms.isNativeSQL()?em.createNativeQuery(stms.toString()):em.createQuery(stms.toString());
        List<Object> values = stms.getParams();
        Integer begin = page.getPageNumber()*page.getPageSize();
        Integer size = page.getPageSize();
        query.setFirstResult(begin);
        query.setMaxResults(size);

        if(stms.isNativeSQL()){
            query.unwrap(NativeQueryImpl.class).setResultTransformer(Transformers.aliasToBean(cls));
        }

        if(values!=null){
            for(int i = 1;i<=values.size();i++){
                query.setParameter(i,values.get(i-1));
            }
        }

        return query;
    }

    public Query createPageQuery(Statement stms,Pageable page){
        Query query = stms.isNativeSQL()?em.createNativeQuery(stms.toString()):em.createQuery(stms.toString());
        List<Object> values = stms.getParams();
        Integer begin = page.getPageNumber()*page.getPageSize();
        Integer size = page.getPageSize();
        query.setFirstResult(begin);
        query.setMaxResults(size);

        // 原生转
        if(stms.isNativeSQL()){
            query.unwrap(NativeQueryImpl.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
        }

        if(values!=null){
            for(int i = 1;i<=values.size();i++){
                query.setParameter(i,values.get(i-1));
            }
        }

        return query;
    }


    public Long total(Statement stms){
        String countSql = stms.countSQL();
        Query query = stms.isNativeSQL()?em.createNativeQuery(countSql):em.createQuery(countSql);
        List<Object> values = stms.getParams();
        if(values!=null){
            for(int i = 1;i<=values.size();i++){
                query.setParameter(i,values.get(i-1));
            }
        }
        return Long.parseLong(query.getSingleResult().toString());//query.getSingleResult();
    }


    public Long findCount(Statement stms){
        String sql = stms.toString();
        Query query = stms.isNativeSQL()?em.createNativeQuery(sql):em.createQuery(sql);
        List<Object> values = stms.getParams();
        if(values!=null){
            for(int i = 1;i<=values.size();i++){
                query.setParameter(i,values.get(i-1));
            }
        }
        return Long.parseLong(query.getSingleResult().toString());//query.getSingleResult();
    }

    public <T> T findObject(Statement stms, Class cls){
        Query query = stms.isNativeSQL()?em.createNativeQuery(stms.toString()):em.createQuery(stms.toString());
        List<Object> values = stms.getParams();
        if(stms.isNativeSQL()){
            query.unwrap(NativeQueryImpl.class).setResultTransformer(Transformers.aliasToBean(cls));
        }
        if(values!=null){
            for(int i = 1;i<=values.size();i++){
                query.setParameter(i,values.get(i-1));
            }
        }
        List<T> list = query.getResultList();
        if(list.size()>0){
            return list.get(0);
        }
        return null;
    }


    public Object findSingleObject(Statement stms){
        Query query = stms.isNativeSQL()?em.createNativeQuery(stms.toString()):em.createQuery(stms.toString());
        List<Object> values = stms.getParams();
        if(values!=null){
            for(int i = 1;i<=values.size();i++){
                query.setParameter(i,values.get(i-1));
            }
        }

        try{
            return query.getSingleResult();
        }catch(Exception e){
            return null;
        }
    }

    public Map<String,Object> findToMap(Statement stms){
        Query query = stms.isNativeSQL()?em.createNativeQuery(stms.toString()):em.createQuery(stms.toString());
        List<Object> values = stms.getParams();
        if(stms.isNativeSQL()){
            query.unwrap(NativeQueryImpl.class)
                    .setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
        }
        if(values!=null){
            for(int i = 1;i<=values.size();i++){
                query.setParameter(i,values.get(i-1));
            }
        }
        // fixed : No entity found for query
        if(query.getResultList().size()==0){
            return null;
        }
        return  (Map<String, Object>) query.getSingleResult();
    }

    public <T> T getObject(Class cls,Integer id){
        return (T) em.find(cls,id);
    }

    public <T> T findObject(Class cls,Long id){
        return (T) em.find(cls,id);
    }
    public void saveObject(Object object){
        em.persist(object);
    }
    public void updateObject(Object obj){
        em.merge(obj);
    }
    public void deleteObject(Object obj){
        em.remove(obj);
    }

}
